package com.medical.literature.document.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.medical.literature.common.exception.BusinessException;
import com.medical.literature.common.vo.PageResult;
import com.medical.literature.common.vo.Result;
import com.medical.literature.document.dto.LiteratureQueryRequest;
import com.medical.literature.document.dto.LiteratureResponse;
import com.medical.literature.document.dto.LiteratureUploadFormData;
import com.medical.literature.document.dto.RecognitionRequest;
import com.medical.literature.document.dto.RecognitionResult;
import com.medical.literature.document.entity.Literature;
import com.medical.literature.document.entity.LiteratureContent;
import com.medical.literature.document.entity.UserFavorite;
import com.medical.literature.document.mapper.LiteratureContentMapper;
import com.medical.literature.document.mapper.LiteratureMapper;
import com.medical.literature.document.mapper.UserFavoriteMapper;
import com.medical.literature.document.service.FileStorageService;
import com.medical.literature.document.service.LiteratureService;
import com.medical.literature.document.service.RecognitionServiceClient;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

/**
 * 文献服务实现类
 */
@Service
@RequiredArgsConstructor
public class LiteratureServiceImpl implements LiteratureService {
    
    // 手动添加log变量
    private static final Logger log = LoggerFactory.getLogger(LiteratureServiceImpl.class);
    
    private final LiteratureMapper literatureMapper;
    private final UserFavoriteMapper userFavoriteMapper;
    private final FileStorageService fileStorageService;
    private final RecognitionResultProcessor recognitionResultProcessor;
    private final RecognitionServiceClient recognitionServiceClient;

    @Override
    @Transactional
    public Long uploadLiteratureFormData(LiteratureUploadFormData request, Long userId, Integer userType) {
        log.info("开始上传文献，用户ID: {}, 用户类型: {}", userId, userType);
        // 检查用户类型，管理员不能上传文献
        if (userType != null && userType == 2) {
            log.warn("管理员不能上传文献");
            throw new BusinessException("管理员不能上传文献");
        }
        
        // 存储文件
        String filePath = fileStorageService.storeFile(request.getFile(), userId);
        log.info("文件存储成功，文件路径: {}", filePath);
        
        // 创建文献记录
        Literature literature = new Literature();
        literature.setTitle(StringUtils.hasText(request.getTitle()) ? 
                          request.getTitle() : request.getFile().getOriginalFilename());
        literature.setAuthors(request.getAuthors());
        literature.setAbstractText(request.getAbstractText());
        literature.setKeywords(request.getKeywords());
        literature.setJournal(request.getJournal());
        
        // 手动转换日期字符串为LocalDate
        if (StringUtils.hasText(request.getPublicationDate())) {
            try {
                LocalDate publicationDate = LocalDate.parse(request.getPublicationDate(), 
                    DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                literature.setPublicationDate(publicationDate);
            } catch (DateTimeParseException e) {
                log.warn("日期解析失败: {}", request.getPublicationDate());
                // 如果日期解析失败，可以设置为null或者抛出异常
                literature.setPublicationDate(null);
            }
        }
        
        literature.setDoi(request.getDoi());
        literature.setFileUrl(filePath);
        literature.setFileName(request.getFile().getOriginalFilename());
        literature.setFileSize(request.getFile().getSize());
        literature.setFileType(request.getFile().getContentType());
        literature.setStatus(1); // 正常状态
        literature.setRecognitionStatus(0); // 未识别
        literature.setUploadUserId(userId);
        
        int result = literatureMapper.insert(literature);
        if (result <= 0) {
            log.error("文献上传失败");
            throw new BusinessException("文献上传失败");
        }
        
        // 不再自动启动文献识别任务，等待管理员手动触发
        log.info("文献上传成功: {} by user {}，等待管理员触发识别，文献ID: {}", literature.getTitle(), userId, literature.getId());
        return literature.getId();
    }

    /**
     * 异步启动文献识别任务
     * @param literatureId 文献ID
     * @param filePath 文件路径
     * @param fileType 文件类型
     */
    @Async
    public void startLiteratureRecognitionAsync(Long literatureId, String filePath, String fileType) {
        try {
            log.info("开始启动文献识别任务，文献ID: {}, 文件路径: {}, 文件类型: {}", literatureId, filePath, fileType);
            // 构造识别请求
            RecognitionRequest recognitionRequest = new RecognitionRequest();
            recognitionRequest.setLiteratureId(literatureId);
            recognitionRequest.setFilePath(filePath);
            recognitionRequest.setFileType(fileType);
            recognitionRequest.setRecognitionType(4); // 4表示全部处理
            
            log.info("构造识别请求完成，准备调用识别服务");
            log.debug("识别请求详情: literatureId={}, filePath={}, fileType={}, recognitionType={}", 
                recognitionRequest.getLiteratureId(), recognitionRequest.getFilePath(), 
                recognitionRequest.getFileType(), recognitionRequest.getRecognitionType());
            
            // 添加更多日志来诊断Feign调用
            log.info("准备调用识别服务，服务名称: recognition-service, 接口: /recognition/process");
            log.debug("识别请求对象详情: {}", recognitionRequest);
            
            // 调用识别服务
            Result<RecognitionResult> result = null;
            try {
                log.info("开始调用识别服务");
                result = recognitionServiceClient.processRecognition(recognitionRequest);
                
                log.info("识别服务调用完成");
                if (result != null) {
                    log.info("识别服务返回结果: code={}, message={}, data is null={}", 
                        result.getCode(), result.getMessage(), result.getData() == null);
                    if (result.getData() != null) {
                        RecognitionResult data = result.getData();
                        log.info("识别结果详情: literatureId={}, status={}, textLength={}, keywordsCount={}", 
                            data.getLiteratureId(), data.getStatus(), 
                            data.getTextContent() != null ? data.getTextContent().length() : 0,
                            data.getKeywords() != null ? data.getKeywords().size() : 0);
                    } else {
                        log.warn("识别服务返回的Result对象中data为null");
                    }
                    
                    // 添加调试日志，查看返回的JSON格式
                    try {
                        com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                        mapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule());
                        String jsonResponse = mapper.writeValueAsString(result);
                        log.debug("识别服务返回的JSON响应: {}", jsonResponse);
                    } catch (Exception e) {
                        log.error("反序列化响应对象时出错: {}", e.getMessage(), e);
                    }
                }
                
                if (result != null && result.isSuccess()) {
                    log.info("文献识别任务启动成功，文献ID: {}", literatureId);
                    
                    // 处理识别结果
                    recognitionResultProcessor.processRecognitionResult(literatureId, result);
                } else {
                    log.error("识别服务调用失败: {}", 
                        (result != null ? result.getMessage() : "未知错误"));
                    throw new BusinessException("识别服务调用失败: " + 
                        (result != null ? result.getMessage() : "未知错误"));
                }
            } catch (Exception e) {
                log.error("调用识别服务时发生异常: {}", e.getMessage(), e);
                // 添加更详细的异常信息
                if (e.getCause() != null) {
                    log.error("异常原因: {}", e.getCause().getMessage(), e.getCause());
                }
                throw new BusinessException("调用识别服务时发生异常: " + e.getMessage());
            }
            
        } catch (Exception e) {
            log.error("启动文献识别任务失败，文献ID: {}", literatureId, e);
            // 更新文献识别状态为失败
            Literature literature = new Literature();
            literature.setId(literatureId);
            literature.setRecognitionStatus(3); // 识别失败
            literatureMapper.updateById(literature);
            
            // 重新抛出异常，确保上层能够捕获到
            throw e;
        }
    }

    @Override
    public PageResult<LiteratureResponse> getLiteratureList(LiteratureQueryRequest query, Long userId) {
        log.info("获取文献列表，用户ID: {}, 查询条件: {}", userId, query);
        Page<LiteratureResponse> page = new Page<>(query.getCurrent(), query.getSize());
        IPage<LiteratureResponse> resultPage = literatureMapper.selectLiteraturePage(page, query, userId);
        
        PageResult<LiteratureResponse> result = new PageResult<>(
                resultPage.getRecords(),
                resultPage.getTotal(),
                resultPage.getSize(),
                resultPage.getCurrent()
        );
        log.info("文献列表获取完成，记录数: {}", result.getRecords().size());
        return result;
    }

    @Override
    public LiteratureResponse getLiteratureById(Long id, Long userId) {
        log.info("获取文献详情，文献ID: {}, 用户ID: {}", id, userId);
        Literature literature = literatureMapper.selectById(id);
        if (literature == null || literature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        LiteratureResponse response = new LiteratureResponse();
        BeanUtils.copyProperties(literature, response);
        
        // 检查是否已收藏
        LambdaQueryWrapper<UserFavorite> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserFavorite::getUserId, userId)
               .eq(UserFavorite::getLiteratureId, id);
        response.setIsFavorite(userFavoriteMapper.selectCount(wrapper) > 0);
        
        log.info("文献详情获取完成，文献ID: {}", id);
        return response;
    }

    @Override
    @Transactional
    public void updateLiterature(Long id, Literature literature, Long userId) {
        log.info("更新文献信息，文献ID: {}, 用户ID: {}", id, userId);
        Literature existingLiterature = literatureMapper.selectById(id);
        if (existingLiterature == null || existingLiterature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        // 检查权限，只有上传者才能修改
        if (!existingLiterature.getUploadUserId().equals(userId)) {
            log.warn("用户 {} 无权限修改文献 {}", userId, id);
            throw new BusinessException("无权限修改该文献");
        }
        
        // 更新文献信息
        literature.setId(id);
        literature.setUpdateTime(LocalDateTime.now());
        int result = literatureMapper.updateById(literature);
        if (result <= 0) {
            log.error("文献更新失败，文献ID: {}", id);
            throw new BusinessException("文献更新失败");
        }
        
        log.info("文献更新成功，文献ID: {}", id);
    }

    @Override
    @Transactional
    public void deleteLiterature(Long id, Long userId) {
        log.info("删除文献，文献ID: {}, 用户ID: {}", id, userId);
        Literature literature = literatureMapper.selectById(id);
        if (literature == null || literature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        // 检查权限，只有上传者才能删除
        if (!literature.getUploadUserId().equals(userId)) {
            log.warn("用户 {} 无权限删除文献 {}", userId, id);
            throw new BusinessException("无权限删除该文献");
        }
        
        // 逻辑删除
        Literature updateLiterature = new Literature();
        updateLiterature.setId(id);
        updateLiterature.setStatus(0); // 标记为删除状态
        updateLiterature.setUpdateTime(LocalDateTime.now());
        int result = literatureMapper.updateById(updateLiterature);
        if (result <= 0) {
            log.error("文献删除失败，文献ID: {}", id);
            throw new BusinessException("文献删除失败");
        }
        
        log.info("文献删除成功，文献ID: {}", id);
    }

    @Override
    public void downloadLiterature(Long id, Long userId, HttpServletResponse response) {
        log.info("下载文献，文献ID: {}, 用户ID: {}", id, userId);
        Literature literature = literatureMapper.selectById(id);
        if (literature == null || literature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        // 检查文件是否存在
        String filePath = literature.getFileUrl();
        if (!fileStorageService.fileExists(filePath)) {
            log.error("文献文件不存在，文件路径: {}", filePath);
            throw new BusinessException("文献文件不存在");
        }
        
        // 设置响应头
        response.setContentType(literature.getFileType() != null ? literature.getFileType() : "application/octet-stream");
        try {
            String encodedFileName = URLEncoder.encode(literature.getFileName(), "UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
        } catch (Exception e) {
            log.warn("文件名编码失败，使用默认名称");
            response.setHeader("Content-Disposition", "attachment; filename=\"literature.pdf\"");
        }
        
        // 输出文件内容
        try (OutputStream outputStream = response.getOutputStream()) {
            byte[] fileBytes = fileStorageService.getFile(filePath);
            outputStream.write(fileBytes);
            outputStream.flush();
        } catch (IOException e) {
            log.error("文件下载失败，文献ID: {}", id, e);
            throw new BusinessException("文件下载失败");
        }
        
        log.info("文献下载成功，文献ID: {}", id);
    }

    @Override
    @Transactional
    public void toggleFavorite(Long id, Long userId) {
        log.info("切换收藏状态，文献ID: {}, 用户ID: {}", id, userId);
        Literature literature = literatureMapper.selectById(id);
        if (literature == null || literature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        // 检查是否已收藏
        LambdaQueryWrapper<UserFavorite> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserFavorite::getUserId, userId)
               .eq(UserFavorite::getLiteratureId, id);
        
        UserFavorite favorite = userFavoriteMapper.selectOne(wrapper);
        if (favorite != null) {
            // 已收藏，取消收藏
            userFavoriteMapper.deleteById(favorite.getId());
            log.info("取消收藏成功，文献ID: {}, 用户ID: {}", id, userId);
        } else {
            // 未收藏，添加收藏
            UserFavorite newFavorite = new UserFavorite();
            newFavorite.setUserId(userId);
            newFavorite.setLiteratureId(id);
            userFavoriteMapper.insert(newFavorite);
            log.info("添加收藏成功，文献ID: {}, 用户ID: {}", id, userId);
        }
    }

    @Override
    public PageResult<LiteratureResponse> getFavoriteList(LiteratureQueryRequest query, Long userId) {
        log.info("获取收藏文献列表，用户ID: {}, 查询条件: {}", userId, query);
        Page<LiteratureResponse> page = new Page<>(query.getCurrent(), query.getSize());
        IPage<LiteratureResponse> resultPage = literatureMapper.selectFavoriteLiteraturePage(page, query, userId);
        
        PageResult<LiteratureResponse> result = new PageResult<>(
                resultPage.getRecords(),
                resultPage.getTotal(),
                resultPage.getSize(),
                resultPage.getCurrent()
        );
        log.info("收藏文献列表获取完成，记录数: {}", result.getRecords().size());
        return result;
    }
    
    @Override
    public void triggerLiteratureRecognition(Long id, Long userId, Integer userType) {
        log.info("手动触发文献识别，文献ID: {}, 用户ID: {}, 用户类型: {}", id, userId, userType);
        // 检查用户权限，只有管理员才能触发识别
        if (userType == null || userType != 2) {
            log.warn("用户 {} 无权限触发文献识别", userId);
            throw new BusinessException("无权限触发文献识别");
        }
        
        Literature literature = literatureMapper.selectById(id);
        if (literature == null || literature.getStatus() == 0) {
            log.error("文献不存在，文献ID: {}", id);
            throw new BusinessException("文献不存在");
        }
        
        // 检查文献状态，允许未识别和识别失败的文献触发识别
        if (literature.getRecognitionStatus() != 0 && literature.getRecognitionStatus() != 3) {
            log.warn("文献 {} 状态不正确，当前状态: {}", id, literature.getRecognitionStatus());
            throw new BusinessException("文献状态不正确，无法触发识别");
        }
        
        // 更新文献状态为识别中
        Literature updateLiterature = new Literature();
        updateLiterature.setId(id);
        updateLiterature.setRecognitionStatus(1); // 识别中
        updateLiterature.setUpdateTime(LocalDateTime.now());
        literatureMapper.updateById(updateLiterature);
        
        // 异步启动识别任务
        startLiteratureRecognitionAsync(id, literature.getFileUrl(), literature.getFileType());
        
        log.info("文献识别任务已启动，文献ID: {}", id);
    }
}